require("socket")--使用LuaSocket模块！

function initConfig()--初始化配置
	--错误页
	error_page_404="ERROR/404.html"
	
	status_code=200--状态码
	
	readContentType()--Content-Type
	
	packageSize=2^12
end

function readContentType()--读取配置的Content-Type
	content_type={}--初始化Table
	for i in io.lines("Config/Content-Type.csv") do--读入文件
		pos=string.find(i,",")--找到","的位置
		name=string.sub(i,1,pos-1)--前面是文件后缀
		content=string.sub(i,pos+1,string.len(i))--后面是相应的Content-Type
		content_type[name]=content--赋值给Table
	end
end

function output(err,infomation)--日志函数
	--初始化输出信息
	temp_info={}
	temp_info[0]="Info"
	temp_info[1]="Warning"
	temp_info[2]="ERROR"
	--输出
	print("[" ..os.date("%Y-%m-%d %H:%M:%S").. "/" ..temp_info[err].. "] " .. infomation)
	temp_info=nil
	--如果是错误就退出
	if(err==2) then
		print("Press any key to continue.")
		io.read()
		os.exit()
	end
end

function init()--初始化
	maxClient=0
	clients={}
	co={}
	
	os.execute("color 7")--更改控制台颜色
	
	initConfig()--初始化配置

	host = "*"--本地主机
	
	if(not(arg[1] == nil)) then--读取用户自定义端口，否则默认80
		port=arg[1]
	else
		port=80
	end
	
	socket0 , err = socket.tcp()--创建TCP对象
	if(socket0==nil) then
		output(2,err)
	else
		output(0,"Create the TCP master object successfully.")
	end
	
	e=socket0:bind(host, port)--绑定
	
	if(e and e==1)then
		output(0,"Bind to host '" ..host.. "' and port " ..port.. " successfully.")
	else
		output(2,"Cannot use the port you choose.Maybe port " .. port.. " has been in use.")  
	end
	
	e =socket0:listen(10)--使用Listen函数将其转化为服务器
	if(e and e ==1)then
		output(0,"Listen to host '" ..host.. "' and port " ..port.. "...")
	else
		output(2,"Listen ERROR : Unknown.")
	end
	
	socket0:settimeout(0.01)
end

function file_exists(filename)--判断文件是否存在
	file=io.open(filename,"rb")--打开文件
	
	if(file ~= nil) then--文件打开失败即为nil
		return true
	else
		return false
	end
end

function readfile(f)--读取文件
	text=""
	
	length=string.len(f)
	
	if(string.sub(f,length,length)=="/") then--请求最后是/就默认读取index.html
		f=f .. "index.html"
	end
	
	if(file_exists(f)) then--存在就返回文件内容
		file=io.open(f,"rb")
		text="Return: " .. f .. " 200 OK."
		
	else
		if(file_exists(f .. "/index.html")) then--不存在1：请求的是目录(如127.0.0.1/web 但其实是想请求127.0.0.1/web/index.html)，看一下下一级有没有index.html
			file=io.open(f .. "/index.html","rb")
			text="Return: " .. f .. " 200 OK."
		else--还是不存在，返回404.html
			file=io.open(error_page_404,"rb")
			text="404 FILE NOT FOUND."
		end
	end
	
	return file:read("*a"),text
end

function process(ta)--处理请求
	t=string.find(ta," HTTP")
	request_file=string.sub(ta,5,t-1)--截取"Get "和" HTTP"间的内容
	return request_file--返回请求的文件
end

function setStatus()--获取状态码
	if(status_code==200) then
	status="OK";
	end
	if(status_code==404) then
	status="NOT FOUND"
	end
end

function setHeader(filename)--设置响应头
header=[=[
HTTP/1.1 ]=] .. status_code .. " " .. status ..[=[

Server:Ink
Content-Type:]=] .. fileType("website" .. filename) .. [=[

Content-Length=]=]
end

function fileType(fff)--获得文件相应的Content-Type
	length=string.len(fff)
	
	if(string.sub(fff,length,length)=="/") then
		fff=fff .. "index.html"
	end

	if(file_exists(fff)==false) then
		if(file_exists(fff .. "/index.html")==true) then
			fff=fff .. "/index.html"
		else
			fff=error_page_404
		end
	end
	
	length=string.len(fff)
	
	name=""
	
	name_length=0

	while(string.sub(name,1,1)~=".") do
		name_length=name_length+1
		name=string.sub(fff,length-name_length,length)
	end
	
	if(content_type[name]~=nil) then
		return content_type[name]
	else
		return "*"
	end
end

function create()
	co[maxClient]=coroutine.create(send)
	clients[maxClient]=client
	maxClient=maxClient+1
end

function pause()
	coroutine.yield(co[nowClient])
end

function send(id)
	local cNow=clients[id]

	output(0,"Client: " .. tostring(cNow))
	
	local request_header
	while(request_header==nil) do--读请求头
		request_header=cNow:receive()
	end
	
	local filename=process(request_header)--处理文件名称
	output(0,"Request: " .. filename)
	
	setStatus()
	
	setHeader(filename)
	
	local file,text=readfile("website"..filename)--读文件
	
	cNow:send(header .. string.len(file) .. "\n\n")--按HTTP1.1的格式头发送
	
	--[[ HTTP响应实例
	
	HTTP/1.1 200 OK
	Server:Ink
	Content-Type:text/html
	Content-Length:12
	
	Hello,world!
	
	]]--
	
	output(0,text .. " Length:" .. string.len(file))
	
	while(file~="") do
		cNow:send(string.sub(file,1,packageSize))
		file=string.sub(file,packageSize+1,string.len(file))
		pause()
	end
	
	cNow:close()--关闭连接
	output(0,"End Connection.")

	co[id]=nil
	clients[id]=nil
end

function listen()
	client=socket0:accept()--连接
	if(client~=nil) then
		create()
	end
end

function manage()
	for nowClient,v in pairs(co) do
		if(v~=nil) then
			coroutine.resume(co[nowClient],nowClient)
		end
	end
end

init()--初始化
while(1) do
	listen()
	manage()
end